package net.tp.algo.text.sa;

/**
 * String as a stream of integer values for suffix array algorithms.
 * <p>
 * Suffix array algorithms usually deal with integer string instead of char string. Therefore, this class is the helper for those algorithms.
 *
 * @author Trung Phan
 */
public abstract class IntString {

    public abstract int charAt(int i);

    public abstract int length();

    public static IntString valueOf(String text) {
        return new StringBackedIntString(text);
    }

    public static IntString valueOf(String text, int beginIndex, int endIndex) {
        return new SubstringBackedIntString(text, beginIndex, endIndex);
    }

    public static IntString valueOf(int[] s) {
        return new IntArrayBackedIntString(s);
    }

    public static class StringBackedIntString extends IntString {

        private final String text;

        private StringBackedIntString(String text) {
            this.text = text;
        }

        @Override
        public int charAt(int i) {
            return (int)text.charAt(i);
        }

        @Override
        public int length() {
            return text.length();
        }
    }

    public static class SubstringBackedIntString extends IntString {

        private final String text;
        private final int beginIndex;
        private final int endIndex;

        private SubstringBackedIntString(String text, int beginIndex, int endIndex) {
            this.text = text;
            this.beginIndex = beginIndex;
            this.endIndex = endIndex;
        }

        @Override
        public int charAt(int i) {
            if (i < 0 || i >= length()) throw new IndexOutOfBoundsException();
            return text.charAt(beginIndex + i);
        }

        @Override
        public int length() {
            return endIndex - beginIndex;
        }
    }

    public static class IntArrayBackedIntString extends IntString {
        private final int[] data;
        public IntArrayBackedIntString(int[] data) {
            this.data = data;
        }

        @Override
        public int charAt(int i) {
            if (i < 0 || i >= data.length) throw new IndexOutOfBoundsException();
            return data[i];
        }

        @Override
        public int length() {
            return data.length;
        }
    }
}
